package grape.file.rest.cloudstorage.mvc;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.URLUtil;
import grape.common.rest.mvc.SuperController;
import grape.file.rest.cloudstorage.form.UploadForm;
import grape.file.rest.cloudstorage.vo.UploadVo;
import grape.file.service.cloudstorage.api.ApiCloudStorageService;
import grape.file.service.cloudstorage.config.CloudStorageConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Optional;

/**
 * 云存储上传控制器
 * 本地存储访问，未添加访问方法，请配合nginx等访问
 * Created by yangwei
 * Created at 2020/3/11 17:43
 */
@Slf4j
@RestController
@RequestMapping(CloudStorageController.API_REQUEST_MAPPING)
@Api(tags = "云存储文件上传下载接口")
public class CloudStorageController extends SuperController {
    public static final String API_REQUEST_MAPPING = "/file/cloudstorage";
    public static final String API_DOWNLOAD = "/download";
    public static final String API_DOWNLOAD_PREFIX = API_REQUEST_MAPPING + API_DOWNLOAD;

    @Autowired
    private List<ApiCloudStorageService> apiCloudStorageServices;

    @Autowired
    private List<CloudStorageConfig> cloudStorageConfigs;
    /**
     * 当前使用的存储上传实现，参考
     * @see grape.file.service.cloudstorage.config.CloudStorageConfig
     * 的实现类的值配置
     */
    @Value("${grape.cloudstorage.upload-type}")
    private String type;

    /**
     * 文件上传 通用上传接口
     *
     * @param uploadForm
     * @return 返回文件的绝对路径
     * @throws IOException
     */
    @ApiOperation("文件上传")
    @PostMapping(value = "/upload")
    @ResponseStatus(HttpStatus.CREATED)
    @ApiImplicitParams({@ApiImplicitParam(paramType = "form", dataType="__file", name = "file",
            value = "上传的文件", required = true)})
    public UploadVo upload(@Valid UploadForm uploadForm) throws IOException {
        log.info("文件上传开始");

        MultipartFile file = uploadForm.getFile();
        InputStream inputStream = file.getInputStream();
        String subPath =  Optional.ofNullable(uploadForm.getPath()).orElse("") + "/" + DateUtil.date().toDateStr() + "/" +  Optional.ofNullable(file.getOriginalFilename()).get();

        String result = null;
        for (ApiCloudStorageService apiCloudStorageService : apiCloudStorageServices) {
            if (apiCloudStorageService.support(type)) {
                result = apiCloudStorageService.upload(inputStream, subPath);
                break;
            }
        }
        IoUtil.close(inputStream);
        // uploadType应该跟grape.file.rest.cloudstorage.mvc.CloudStorageController.download的第二个参数一致
        result += "?uploadType=" + type;
        if (!StringUtils.startsWith(result,"http")) {
            result = getLocalStorageConfig().domain() + API_DOWNLOAD_PREFIX + result;
        }
        log.info("文件上传结束");
        return new UploadVo().setUrl(result);
    }

    /**
     * 下载
     * @param request
     */
    @GetMapping(API_DOWNLOAD + "/**")
    public void download(HttpServletRequest request, HttpServletResponse response,String uploadType) throws Throwable {
        String requestURI = request.getRequestURI();
        requestURI = URLUtil.decode(requestURI);
        String filePath = requestURI.replaceFirst(getPrefix(),"");

        if (isStrEmpty(uploadType)) {
            uploadType = getLocalStorageConfig().uploadType();
        }
        byte[] result = null;
        for (ApiCloudStorageService apiCloudStorageService : apiCloudStorageServices) {
            if (apiCloudStorageService.support(uploadType)) {
                result = apiCloudStorageService.download(filePath);
                break;
            }
        }
        if (result != null) {
            InputStream inputStream = new ByteArrayInputStream(result);
            OutputStream stream = response.getOutputStream();
            IoUtil.copy(inputStream,stream);
            IoUtil.close(inputStream);
            IoUtil.close(stream);
        }
    }
    /**
     * 删除
     * @param request
     */
    @DeleteMapping( API_DOWNLOAD + "/**")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(HttpServletRequest request, HttpServletResponse response,String uploadType){
        String requestURI = request.getRequestURI();
        requestURI = URLUtil.decode(requestURI);
        String filePath = requestURI.replaceFirst(getPrefix(),"");

        if (isStrEmpty(uploadType)) {
            uploadType = getLocalStorageConfig().uploadType();
        }
        int result;
        for (ApiCloudStorageService apiCloudStorageService : apiCloudStorageServices) {
            if (apiCloudStorageService.support(uploadType)) {
                result = apiCloudStorageService.delete(filePath);
                break;
            }
        }
    }

    private CloudStorageConfig getLocalStorageConfig(){
        return cloudStorageConfigs.stream().filter(item -> item.isLocalStorage()).findFirst().orElseThrow(()->new RuntimeException("没有找到本地存储配置，请检查配置"));
    }
    public String getPrefix(){
        return API_DOWNLOAD_PREFIX;
    }
}
